package com.siyu.prewarn.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.siyu.basedata.plan.domain.Plan;
import com.siyu.basedata.plan.service.IPlanService;
import com.siyu.basedata.rsvrrlaste.domain.RsvrRLaste;
import com.siyu.basedata.rsvrrlaste.service.IRsvrRLasteService;
import com.siyu.basedata.wrprsrhych.domain.WrpRsrHych;
import com.siyu.basedata.wrprsrhych.service.IWrpRsrHychService;
import com.siyu.basedata.wrprsrwlstcparrl.domain.Wrprsrwlstcparrl;
import com.siyu.basedata.wrprsrwlstcparrl.service.IwrprsrwlstcparrlService;
import com.siyu.basedata.xajresult.domain.XajResult;
import com.siyu.basedata.xajresult.service.IXajResultService;
import com.siyu.common.utils.uuid.IdUtils;
import com.siyu.predict.utils.DataServiceUtil;
import com.siyu.predict.utils.DataUtil;
import com.siyu.prewarn.dto.SendDto;
import com.siyu.prewarn.dto.TimeDto;
import com.siyu.prewarn.mesuser.domain.Mesuser;
import com.siyu.prewarn.mesuser.service.IMesuserService;
import com.siyu.prewarn.sendway.domain.SendWay;
import com.siyu.prewarn.sendway.service.ISendWayService;
import com.siyu.prewarn.service.IPrewarnService;
import com.siyu.prewarn.skreservoirdutyperson.domain.SkReservoirDutyPerson;
import com.siyu.prewarn.skreservoirdutyperson.service.ISkReservoirDutyPersonService;
import com.siyu.prewarn.warncondition.domain.WarnCondition;
import com.siyu.prewarn.warncondition.service.IWarnConditionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PrewarnServiceImpl implements IPrewarnService {
    @Autowired
    private IXajResultService xajResultService;
    @Autowired
    private IPlanService planService;
    @Autowired
    private IRsvrRLasteService rsvrRLasteService;
    @Autowired
    private IWrpRsrHychService wrpRsrHychService;
    @Autowired
    private IWarnConditionService warnConditionService;
    @Autowired
    private ISendWayService sendWayService;
    @Autowired
    private IwrprsrwlstcparrlService wrprsrwlstcparrlService;
    @Autowired
    private ISkReservoirDutyPersonService skReservoirDutyPersonService;

    @Override
    public HashMap<Object, Object> getRaindata(Integer tms, String rscd) throws Exception {

        Date endTime = new Date();
        LocalDateTime nowDateTime = LocalDateTime.ofInstant(endTime.toInstant(), ZoneOffset.systemDefault()); // 转换为LocalDateTime
        LocalDateTime dateBefore24Hours = nowDateTime.minus(tms / 24, ChronoUnit.DAYS); // 减去一天
        Date startTime = Date.from(dateBefore24Hours.atZone(ZoneId.systemDefault()).toInstant()); // 转回Date类型

        HashMap<Object, Object> areaRainfall = DataUtil.getAreaRainfall(rscd, startTime, endTime, 1);
        return areaRainfall;
    }

    @Override
    public HashMap<Object, Object> getData(String id) {
        HashMap<Object, Object> map = new HashMap<>();
        try {
            QueryWrapper<XajResult> xajResultQueryWrapper = new QueryWrapper<>();
            xajResultQueryWrapper.select("id", "tm", "pre_q", "pre_z", "check_q", "net_rain", "area_rain")
                    .eq("plan_id", id).orderByAsc("tm");
            List<XajResult> list = xajResultService.list(xajResultQueryWrapper);
            // 预报数据
            map.put("xajData", list);
            // 统计预报信息
            Map<String, Object> resultMap = DataUtil.getTotalDetail(list);
            map.put("counts", resultMap);
            // 水库特征数据查询
            Plan plan = planService.getById(id);
            QueryWrapper<WrpRsrHych> wrpRsrHychQueryWrapper = new QueryWrapper<>();
            wrpRsrHychQueryWrapper.eq("rscd", plan.getRscd());
            WrpRsrHych one = wrpRsrHychService.getOne(wrpRsrHychQueryWrapper);
            map.put("rsvr", one);
            // 预警数据
            List<XajResult> xajResults = new ArrayList<>();
            // 汛限水位
            Optional<XajResult> firstExceedingElement = list.stream()
                    .filter(xajResult -> xajResult.getPreZ() > one.getMjflsscnwl())
                    .findFirst();
            XajResult result = firstExceedingElement.orElse(null);
            if (result != null) {
                xajResults.add(result);
            }
            // 设计洪水位
            Optional<XajResult> firstExceedingElement2 = list.stream()
                    .filter(xajResult -> xajResult.getPreZ() > one.getDsfllv())
                    .findFirst();
            XajResult result2 = firstExceedingElement2.orElse(null);
            if (result2 != null) {
                xajResults.add(result2);
            }
            // 校核洪水位
            Optional<XajResult> firstExceedingElement3 = list.stream()
                    .filter(xajResult -> xajResult.getPreZ() > one.getChfllv())
                    .findFirst();
            XajResult result3 = firstExceedingElement3.orElse(null);
            if (result3 != null) {
                xajResults.add(result3);
            }
            map.put("warnMes", xajResults);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return map;
    }

    @Override
    public HashMap<Object, Object> getWarnData(String rscd) throws Exception {
        // 获取当前时间
        Date endTime = DateUtil.parse(DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:00:00")).toJdkDate();
        //  往前推24h
        Date startTime = DateUtil.offsetHour(endTime, -24).toJdkDate();
//        HashMap<Object, Object> areaRainfall = DataUtil.getpreAreaRainfall(rscd, startTime, endTime, 1);
        HashMap<Object, Object> areaRainfall = DataServiceUtil.getDrpVoList(rscd, startTime, endTime, 1);
        List<Double> areaRain = Convert.toList(Double.class, areaRainfall.get("areaRain"));
        Double totalRain = areaRain.stream().mapToDouble(Double::doubleValue).sum();
        // 确定降雨等级
        String rainGrade = getRainGrade(totalRain);
        HashMap<Object, Object> map1 = new HashMap<>();
        map1.put("totalRain", totalRain);
        map1.put("rainGrade", rainGrade);
        // 查询水库监测信息
//        QueryWrapper<RsvrRLaste> rsvrRQueryWrapper = new QueryWrapper<>();
//        rsvrRQueryWrapper.eq("stcd", rscd).le("tm",new Date()).apply("date_trunc('hour', tm) = tm").orderByDesc("tm").last("LIMIT 10");
//        List<RsvrRLaste> list = rsvrRLasteService.list(rsvrRQueryWrapper);

        DateTime date = DateUtil.parse(new SimpleDateFormat("yyyy-MM-dd HH:00:00").format(new Date()));
        List<RsvrRLaste> list = DataServiceUtil.getRsvrVoList(rscd, DateUtil.offsetDay(date, -1), date, 1);
        HashMap<Object, Object> map2 = new HashMap<>();
        map2.put("rz", list.get(0).getRz());
        map2.put("change", NumberUtil.round(list.get(0).getRz() - list.get(1).getRz(), 2));

        List<Wrprsrwlstcparrl> wrprsrwlstcparrls = wrprsrwlstcparrlService.lambdaQuery().eq(Wrprsrwlstcparrl::getRscd, rscd).orderByAsc(Wrprsrwlstcparrl::getWl).list();
        // 获取库容曲线序列
        List<Double> w = wrprsrwlstcparrls.stream().map(Wrprsrwlstcparrl::getStcp).collect(Collectors.toList());//库容量
        List<Double> z = wrprsrwlstcparrls.stream().map(Wrprsrwlstcparrl::getWl).collect(Collectors.toList());// 水位
        Double data = DataUtil.getData(z, w, list.get(0).getRz());
//        map2.put("w", list.get(0).getW());
        map2.put("w", data);
        // 纳雨数据
        HashMap<Object, Object> map3 = accRain(list.get(0).getRz(),rscd);
//        HashMap<Object, Object> map3 = new HashMap<>();
//        map3.put("towarn", 143.87);
//        map3.put("tocheck", 187.68);

        HashMap<Object, Object> map = new HashMap<>();
        map.put("nayu", map3);
        map.put("rain", map1);
        map.put("rsvr", map2);
        return map;
    }

    @Override
    public List<WarnCondition> getWarnMes(TimeDto timeDto) {
        QueryWrapper<WarnCondition> wrapper = new QueryWrapper<>();
        wrapper.eq("rscd", timeDto.getRscd())
                .ge(BeanUtil.isNotEmpty(timeDto.getStartTime()), "warn_time", timeDto.getStartTime())
                .le(BeanUtil.isNotEmpty(timeDto.getEndTime()), "warn_time", timeDto.getEndTime()).orderByDesc("create_time");
        List<WarnCondition> list = warnConditionService.list(wrapper);
        for (WarnCondition warnCondition : list) {
            HashMap<Object, Object> map = new HashMap<>();
            // 发送方式
            List<String> sendIdss = JSONUtil.toList(warnCondition.getSendWay(), String.class).stream().collect(Collectors.toList());
            List<SendWay> sendWays = sendIdss.stream().map(sendWayService::getById).collect(Collectors.toList());
            // 发送对象
//            List<Long> userIds = JSONUtil.toList(warnCondition.getUserIds(), Long.class).stream().collect(Collectors.toList());
//            List<SkReservoirDutyPerson> mesusers = userIds.stream().map(skReservoirDutyPersonService::getById).collect(Collectors.toList());
            String mesusers = warnCondition.getUserIds();
            JSONArray jsonArray = new JSONArray(mesusers);
            map.put("sendWays", sendWays);
            map.put("mesusers", jsonArray);
            warnCondition.setDetail(map);
        }
        return list;
    }


    @Override
    public void saveWarnMes(SendDto sendDto) {
        WarnCondition warnCondition = new WarnCondition();
        warnCondition.setRscd(sendDto.getRscd());
        warnCondition.setId(IdUtils.getId());
        warnCondition.setWarnType("水位预报");
        warnCondition.setSendContent(sendDto.getSendContent());
        if (BeanUtil.isNotEmpty(sendDto.getXajResult())){
            warnCondition.setWarnData("水位值达到"+sendDto.getXajResult().getPreZ().toString()+"米,"+"超过汛限水位！");
            warnCondition.setWarnTime(DateUtil.parse(sendDto.getXajResult().getTm()));
        }else {
            warnCondition.setWarnData(sendDto.getSendContent());
            warnCondition.setWarnTime(new Date());
        }
        warnCondition.setState(1);
        warnCondition.setSendWay(JSONUtil.toJsonStr(sendDto.getSendWay()));
//        warnCondition.setUserIds(JSONUtil.toJsonStr(sendDto.getUserIds()));
        warnCondition.setUserIds(JSONUtil.toJsonStr(sendDto.getSendObj()));
        warnCondition.setCreateTime(new Date());
        warnCondition.setCName(sendDto.getCname());
        warnConditionService.save(warnCondition);
    }

    /**
     * 降雨等级查询
     * @param totalRain
     * @return
     */
    private String getRainGrade(Double totalRain) {
        if (totalRain < 0.1) {
            return "无雨";
        } else if (totalRain >= 0.1 && totalRain <= 10) {
            return "小雨";
        } else if (totalRain > 10 && totalRain <= 25) {
            return "中雨";
        } else if (totalRain > 25 && totalRain <= 50) {
            return "大雨";
        } else if (totalRain > 50 && totalRain <= 100) {
            return "暴雨";
        } else if (totalRain > 100 && totalRain <= 250) {
            return "大暴雨";
        } else {
            return "特大暴雨";
        }
    }


    /**
     * 纳雨数据
     * @param rz 实测水位
     * @param rscd
     * @return
     */
    private HashMap<Object, Object> accRain(Double rz, String rscd) {
        // 查询水库特征信息
        WrpRsrHych wrpRsrHych = wrpRsrHychService.lambdaQuery().eq(WrpRsrHych::getRscd, rscd).one();
        Double warnZ = wrpRsrHych.getMjflsscnwl(); // 汛限水位
        Double checkZ = wrpRsrHych.getChfllv(); // 校核水位
        // 库容曲线
        List<Double> z = new ArrayList<>();
        List<Double> w = new ArrayList<>();
        wrprsrwlstcparrlService.lambdaQuery().eq(Wrprsrwlstcparrl::getRscd, rscd).orderByAsc(Wrprsrwlstcparrl::getWl).list().forEach(wrprsrwlstcparrl -> {
            z.add(wrprsrwlstcparrl.getWl());
            w.add(wrprsrwlstcparrl.getStcp());
        });
        // 获取当前库容
        Double currentW = DataUtil.getData(w, z, rz);
        // 获取汛限库容
        Double warnW = DataUtil.getData(w, z, warnZ);
        // 获取校核库容
        Double checkW = DataUtil.getData(w, z, checkZ);
        HashMap<Object, Object> map = new HashMap<>();
        map.put("towarn", NumberUtil.round((warnW-currentW)*100000/(wrpRsrHych.getCnctar()*0.56),2));
        map.put("tocheck",NumberUtil.round( (checkW-currentW)*100000/(wrpRsrHych.getCnctar()*0.56),2));
        return map;
    }


}
